/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Copyright 2002-2003 by Mark Wolgemuth, All rights reserved.             */
/* Copyright 2002-2003 by Employease, Inc.  All rights reserved.           */
/*                                                                         */
/* Redistribution and use in source and binary forms, with or without      */
/* modification, are permitted provided that the following conditions      */
/* are met:                                                                */
/*                                                                         */
/*    1. Redistributions of source code must retain the above copyright    */
/* notice, this list of conditions and the following disclaimer.           */
/*    2. Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in the     */
/* documentation and/or other materials provided with the distribution.    */
/*                                                                         */
/* THIS SOFTWARE IS PROVIDED BY THE MOD_ATHENA PROJECT ``AS IS'' AND ANY   */
/* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE       */
/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR      */
/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR        */
/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,   */
/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,     */
/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR      */
/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT            */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE   */
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "ath_lb.h"

/* wraps ath_shm_enginebase() to return engine */
ath_engine * 
ath_engine_get()
{
    ath_engine *engine = ath_shm_enginebase();
    ASSERT(engine);
    return engine;
}

/* configure engine from apache config object */
ath_engine * 
ath_engine_configure(apr_pool_t *pool, ath_conf_ap *aconf)
{
    int i = 0;
    char *str_algo;
    ath_engine *engine = ath_engine_get();
    ASSERT(aconf);

    engine->default_phys_on = aconf->engine_default_phys_on;
    engine->default_farm_on = aconf->engine_default_farm_on;
    ath_shm_strncpy(engine->path, aconf->engine_path, ATH_NAME_MAX);
    if (aconf->engine_down_url)
	ath_shm_strncpy(engine->down_url, aconf->engine_down_url, ATH_NAME_MAX);
    if (aconf->engine_offline_url)
	ath_shm_strncpy(engine->offline_url, aconf->engine_offline_url, ATH_NAME_MAX);
    engine->expect_update = aconf->engine_expect_update;
    if (aconf->engine_expect_update_field != ATH_ALGO_NON)
	engine->expect_update_field = aconf->engine_expect_update_field;
    engine->nominate_per_update = aconf->engine_nominate_per_update;
    engine->allow_ttl = aconf->engine_allow_ttl;
    engine->recover_ttl = aconf->engine_recover_ttl;
    if (aconf->engine_algo != NULL)
	str_algo = 
	  apr_pstrndup(pool, aconf->engine_algo, strlen(aconf->engine_algo));
    ath_algo_def_from_str(engine->algo_def, str_algo);
    engine->hit_adds_to = aconf->engine_hit_adds_to;
    engine->hit_adds = aconf->engine_hit_adds;
    engine->algo_def->max_excluded = aconf->engine_max_excluded;
    engine->smartfarming = aconf->smartfarm_enable;
    return engine;
}

/* to protect the rest of the engine when only stats needed */
ath_engine_stat * 
ath_engine_stat_get()
{
    ath_engine *engine = ath_shm_enginebase();
    ASSERT(engine);
    return engine->stats;
}

/* formats shm chunk for engine */
void 
ath_engine_format(ath_engine *engine)
{
    int i;
    for (i = 0; i < ATH_NAME_MAX; i++)
      {
	  engine->path[i] = (int) NULL; /* clear path */
	  engine->down_url[i] = (int) NULL; /* clear global down URL */
	  engine->offline_url[i] = (int) NULL; /* clear global down URL */
      }
    /* format algo_def: farms will be set to this unless config exists */
    ath_algo_def_format(engine->algo_def);
    engine->hit_adds_to = (int) NULL;
    engine->hit_adds = 0;
    engine->default_farm_on = ATH_OFF;
    engine->default_phys_on = ATH_OFF;
    engine->expect_update = 0;
    engine->expect_update_field = ATH_ALGO_NON;
    engine->allow_ttl = 0;
    engine->smartfarming = 0;
    engine->farm_count = 0;
    engine->phys_count = 0;
    engine->lock_idx = 0;
    engine->stats->hits_reject = 0;
    engine->stats->hits_error = 0;
    engine->stats->hits_status = 0;
    engine->stats->hits_update = 0;
    engine->stats->hits_balance = 0;
    engine->stats->hits_downurl = 0;
    engine->stats->hits_offlineurl = 0;
    engine->stats->hits_mirror = 0;
    engine->stats->hits_smartfarm = 0;
    engine->stats->hits_smartfarm_tamper = 0;
/*     engine->stats->hits_smartfarm_undef = 0; */
/*     engine->stats->hits_smartfarm_broken = 0; */
/*     engine->stats->hits_smartfarm_prepend = 0; */
/*     engine->stats->hits_smartfarm_postpend = 0; */
/*     engine->stats->hits_smartfarm_replace = 0; */
/*     engine->stats->hits_smartfarm_sticky = 0; */
/*     engine->stats->hits_smartfarm_blind = 0; */
/*     engine->stats->hits_smartfarm_match = 0; */
/*     engine->stats->hits_smartfarm_regex = 0; */
    for (i = 0; i < ATH_FARM_HARDMAX; i++)
	engine->stats->hits_idx_farm[i] = 0;
    for (i = 0; i < ATH_FARM_HARDMAX; i++)
	engine->stats->hits_idx_phys[i] = 0;
}

/* format output to str of engine status */
char * 
ath_engine_to_str(apr_pool_t *p, const char *fmt)
{
    int c;
    char *str_out = "";
    ath_engine *engine = ath_engine_get();
    ath_engine_stat *stats = engine->stats;
    ath_farm *farm;
    ath_phys *phys;
    apr_int64_t farm_tot = 0;
    int i;
    ASSERT(fmt);

    while (*fmt != (int) NULL)
      {
	  c = (int) *fmt;
	  if  (c == (int) ATH_CASE_ESC)
	    {
		fmt++;
		c = (int) *fmt;
		switch ((char) c)
		  {
		  case ATH_CASE_E_PATH:
		      str_out = apr_pstrcat(p, str_out, 
					    engine->path, NULL);
		      break;
		  case ATH_CASE_DURL:
		      str_out = apr_pstrcat(p, str_out, 
					    engine->down_url, NULL);
		      break;
		  case ATH_CASE_ALGO:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (ath_algo_def_to_str(p, 
							 engine->algo_def)), 
				    NULL);
		      break;
		  case 'h': /* hit adds */
		      if (engine->hit_adds_to != ATH_ALGO_NON)
			{
			    str_out = 
			      apr_pstrcat(p, str_out, "adds ", 
					  (apr_psprintf(p, "%f", 
							engine->hit_adds)), 
					  " to ", 
					  (ath_algo_type_to_str(engine->hit_adds_to)),
					  NULL);
			}
		      break;
		  case ATH_CASE_EXPECT:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->expect_update)),
				    NULL);
		      break;
		  case ATH_CASE_NOMINA:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->nominate_per_update)),
				    NULL);
		      break;
		  case ATH_CASE_TTL:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->allow_ttl)),
				    NULL);
		      break;
		  case ATH_CASE_RTTL:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->recover_ttl)),
				    NULL);
		      break;
		  case ATH_CASE_FARM:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->farm_count)),
				    NULL);
		      break;
		  case ATH_CASE_PHYS:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%d", 
						  engine->phys_count)),
				    NULL);
		      break;
		  case ATH_CASE_STATS:
		      str_out = 
			apr_pstrcat(p, str_out,
				    (apr_psprintf(p, 
						  "reject: %"APR_INT64_T_FMT
						  "\nerror: %"APR_INT64_T_FMT
						  "\nhello: %"APR_INT64_T_FMT
						  "\nstatus: %"APR_INT64_T_FMT
						  "\nupdate: %"APR_INT64_T_FMT
						  "\nbalance: %"APR_INT64_T_FMT
						  "\ndown url: %"APR_INT64_T_FMT
						  "\noffline url: %"APR_INT64_T_FMT
						  "\nmirror: %"APR_INT64_T_FMT
						  "\nsmartfarm: %"APR_INT64_T_FMT
						  "\nsmartfarm tamper: %"APR_INT64_T_FMT
						  "\n",
						  engine->stats->hits_reject,
						  engine->stats->hits_error,
						  engine->stats->hits_hello,
						  engine->stats->hits_status,
						  engine->stats->hits_update,
						  engine->stats->hits_balance,
						  engine->stats->hits_downurl,
						  engine->stats->hits_offlineurl,
						  engine->stats->hits_mirror,
						  engine->stats->hits_smartfarm,
						  engine->stats->hits_smartfarm_tamper
/* 						  engine->stats->hits_smartfarm_undef, */
/* 						  engine->stats->hits_smartfarm_broken, */
/* 						  engine->stats->hits_smartfarm_prepend, */
/* 						  engine->stats->hits_smartfarm_postpend, */
/* 						  engine->stats->hits_smartfarm_replace, */
/* 						  engine->stats->hits_smartfarm_sticky, */
/* 						  engine->stats->hits_smartfarm_blind, */
/* 						  engine->stats->hits_smartfarm_match, */
/* 						  engine->stats->hits_smartfarm_regex */
						  )
				     ),
				    NULL);
		      for (i = 0; i < engine->farm_count; i++)
			{
			    farm = ath_farm_for_idx(i);
			    str_out = 
			      apr_pstrcat(p, str_out,
					  apr_psprintf(p, "farm: %s: %"APR_INT64_T_FMT"\n",
						       farm->name,
						       engine->stats->hits_idx_farm[i]
						       ),
						  NULL);
			    farm_tot += engine->stats->hits_idx_farm[i];
			}
		      for (i = 0; i < engine->phys_count; i++)
			{
			    phys = ath_phys_for_idx(i);
			    str_out = 
			      apr_pstrcat(p, str_out,
					  apr_psprintf(p, "phys: %s: %"APR_INT64_T_FMT"\n",
						       phys->host,
						       engine->stats->hits_idx_phys[i]
						       ),
						  NULL);
			}
		      str_out = 
			apr_pstrcat(p, str_out,
				    apr_psprintf(p, "total balanced hits: %"APR_INT64_T_FMT"\n",
						 farm_tot),
				    NULL);
		      break;
		  default:
		      str_out = 
			apr_pstrcat(p, str_out, 
				    (apr_psprintf(p, "%%%c", (char) c)), NULL);
		  }
	    }
	  else
	    {
		str_out = apr_pstrcat(p, str_out, 
				      (apr_psprintf(p, "%c", (char) c)), NULL);
	    }
	  fmt++;
      }
    return str_out;
}
